/*
 * Copyright 2020-2030 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
package com.gitee.minimalismstyle.fresh.simple.service.impl

import com.gitee.minimalismstyle.fresh.common.core.conversion.TypeConversion
import com.gitee.minimalismstyle.fresh.common.core.conversion.TypeConversionFactory
import com.gitee.minimalismstyle.fresh.common.core.domain.QueryBody
import com.gitee.minimalismstyle.fresh.common.core.domain.QueryParams
import com.gitee.minimalismstyle.fresh.common.core.domain.R
import com.gitee.minimalismstyle.fresh.common.core.domain.Simple
import com.gitee.minimalismstyle.fresh.common.core.extra.copyProperties
import com.gitee.minimalismstyle.fresh.common.core.spring.SpringContextUtils
import com.gitee.minimalismstyle.fresh.common.data.beetl.service.impl.LongModelBaseServiceImpl
import com.gitee.minimalismstyle.fresh.simple.api.model.*
import com.gitee.minimalismstyle.fresh.simple.api.service.*
import com.gitee.minimalismstyle.fresh.simple.dao.*
import com.gitee.minimalismstyle.fresh.simple.sql.Condition
import com.gitee.minimalismstyle.fresh.sys.api.model.SysDataPermission
import com.gitee.minimalismstyle.fresh.sys.api.service.SysDataPermissionService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/**
 * 列表定义业务实现
 * @author maoxiaodong
*/
@Primary
@Service
class SimpleListServiceImpl: SimpleListService, LongModelBaseServiceImpl<SimpleListDao, SimpleList>(){

    @Autowired
    private lateinit var simpleListFieldService: SimpleListFieldService
    @Autowired
    private lateinit var simpleSqlService: SimpleSqlService
    @Autowired
    private lateinit var simpleActionService: SimpleActionService
    @Autowired
    private lateinit var simpleFormService: SimpleFormService
    @Autowired
    private lateinit var sysDataPermissionService: SysDataPermissionService


    @Transactional
    override fun saveSimpleListFormFields(simpleListFormFields: SimpleListFormFields): R<SimpleListFormFields> {
        if(simpleListFormFields.code.isNullOrEmpty()){
            return R.error("代码不能为空！")
        }

        if(simpleListFormFields.form != null) {
            simpleFormService.saveSimpleFormFields(simpleListFormFields.form).success{
                simpleListFormFields.queryFormId = it!!.id
            }
        }

        if(simpleListFormFields.action != null){
            simpleActionService.saveSimpleActionFields(simpleListFormFields.action).success{
                simpleListFormFields.toolbarActionId = it!!.id
            }
        }
        val simpleList = simpleListFormFields.copyProperties(SimpleList::class)
        dao.save(simpleList)
        simpleList.copyProperties(simpleListFormFields)
        simpleListFormFields.fields.forEach {
            it.reset()
            it.listId =  simpleListFormFields.id
        }
        simpleListFieldService.saveSimpleListFieldActions(simpleListFormFields.fields)
        return R.success(simpleListFormFields)
    }

    override fun copySimpleListFormFields(copySimpleListFormFields: CopySimpleListFormFields): R<SimpleListFormFields> {
        val source = findSimpleListFormFieldsByCode(copySimpleListFormFields.sourceCode).get()
        source.reset()
        source.code = copySimpleListFormFields.targetCode
        source.name = copySimpleListFormFields.targetName
        source.action.code = "${copySimpleListFormFields.targetCode}_list_action"
        source.action.name = "${copySimpleListFormFields.targetName}工具栏"
        source.form.code = "${copySimpleListFormFields.targetCode}_list_form"
        source.form.name = "${copySimpleListFormFields.targetName}查询表单"
        val operate = source.fields.find { it.type == "operate" }
        if(operate != null){
            operate.action?.code = "${copySimpleListFormFields.targetCode}_list_field_action"
            operate.action?.name = "${copySimpleListFormFields.targetName}列操作"
        }
        val simpleListFormFields = saveSimpleListFormFields(source).get()
        return R.success(simpleListFormFields)
    }

    override fun getSimpleSqlParams(code: String, simple: Simple): R<SimpleSqlParams> {
        val simpleList = dao.findByCode(code)
        return getSimpleSqlParams(simpleList, simple)
    }

    override fun findByCode(code: String): R<SimpleList> {
        val simpleList = dao.findByCode(code)
        return R.success(simpleList)
    }

    private fun getSimpleSqlParams(simpleList: SimpleList, queryParams: Simple): R<SimpleSqlParams> {
        val simpleSql = simpleSqlService.findById(simpleList.datasourceId!!.toLong()).get()
        val queryFormId = simpleList.queryFormId
        val sqlBuffer = StringBuffer("select \n")
        sqlBuffer.append("--@pageTag(){\n")
        sqlBuffer.append(" * ")
        sqlBuffer.append("--@}\n")
        sqlBuffer.append(" from (${simpleSql.sql}) t0 where 1=1\n")
        if (queryFormId != null) {
            val simpleForm = simpleFormService.findSimpleFormFieldsById(queryFormId).get()
            simpleForm.fields.forEach {
                if (it.operator != "other") {
                    val condition: Condition = SpringContextUtils.getBean("${it.operator}Condition")
                    condition.add(sqlBuffer, it)

                    if (it.type == "list") {
                        val list = it.value?.split(",")
                        queryParams[it.code!!] = list!!
                    }else if (it.type == "hidden"){
                        if(it.format == "data"){
                            val r = sysDataPermissionService.findByCurrentUser(it.pattern!!)
                            queryParams[it.code!!] = r.get()
                        }
                    }


                }

                val paramValue = queryParams[it.code]
                val typeConversion: TypeConversion<String, *> = TypeConversionFactory.get(String::class.java.name, it.type!!)
                        as TypeConversion<String, *>
                if(paramValue != null){
                    if(paramValue is List<*>){
                        val list = mutableListOf<Any?>()
                        paramValue.forEach { value ->
                            list.add(typeConversion.convert(value.toString(), it.pattern))
                        }
                        queryParams[it.code!!] = list
                    }else{

                        queryParams[it.code!!] = typeConversion.convert(paramValue.toString(), it.pattern)
                    }

                }else if(it.value != null){
                    if(it.operator == "in"
                            || it.operator == "notIn"
                            || it.operator == "between"
                            || it.operator == "betweenEquals"){
                        val list = mutableListOf<Any?>()
                        it.value?.split(",")?.forEach {value ->
                            list.add(typeConversion.convert(value, it.pattern))
                        }
                        queryParams[it.code!!] = list
                    }else{
                        queryParams[it.code!!] = typeConversion.convert(it.value, it.pattern)
                    }

                }
            }
        }

        val simpleSqlParams = SimpleSqlParams(sqlBuffer.toString(), queryParams)
        return R.success(simpleSqlParams)
    }

    override fun findSimpleListFormFieldsByCode(code: String): R<SimpleListFormFields> {
        val simpleList = dao.findByCode(code)
        val simpleListFormFields = simpleList.copyProperties(SimpleListFormFields::class)
        val simpleListFields = simpleListFieldService.findSimpleListFieldActionByListId(simpleList.id!!).get()
        simpleListFormFields.fields = simpleListFields
        if(simpleList.queryFormId != null){
            simpleFormService.findSimpleFormFieldsById(simpleList.queryFormId!!).success{
                simpleListFormFields.form = it!!
            }
        }

        if(simpleList.toolbarActionId != null){
            simpleActionService.findSimpleActionFieldsById(simpleList.toolbarActionId!!).success{
                simpleListFormFields.action = it!!
            }
        }

        return R.success(simpleListFormFields)
    }

    override fun findDataPageByCode(code: String, queryParams: QueryParams<Simple>) : R<QueryBody<Simple>> {
        val simpleList = dao.findByCode(code)
        if(simpleList.datasourceType == "SQL") {
            val simpleSql = simpleSqlService.findById(simpleList.datasourceId!!.toLong()).get()
            val simpleSqlParams = getSimpleSqlParams(simpleList, queryParams.params!!).get()
            simpleSql.sql = simpleSqlParams.sql
            queryParams.params = simpleSqlParams.params
            return simpleSqlService.executePageBySimpleSql(simpleSql, queryParams)
        }
        return R.success()
    }

    override fun findDataByCode(code: String, queryParams: QueryParams<Simple>): R<QueryBody<Simple>> {
        return findDataPageByCode(code, queryParams)
    }
}